package cn.jetpiece.cloud.joss.app.modular.object.controller;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.jetpiece.cloud.core.util.HttpContext;
import cn.jetpiece.cloud.joss.api.object.JossObjectApi;
import cn.jetpiece.cloud.joss.api.object.model.params.*;
import cn.jetpiece.cloud.joss.api.object.model.result.JossPartEtag;
import cn.jetpiece.cloud.joss.api.object.model.result.UploadObjectResult;
import cn.jetpiece.cloud.joss.app.config.properties.OssProperties;
import cn.jetpiece.cloud.joss.app.core.constant.OssConstants;
import cn.jetpiece.cloud.joss.app.core.utils.AuthUtil;
import cn.jetpiece.cloud.joss.app.modular.object.enums.BasicExceptionEnum;
import cn.jetpiece.cloud.joss.app.modular.object.model.BucketInfo;
import cn.jetpiece.cloud.joss.app.modular.object.service.BucketService;
import cn.jetpiece.cloud.joss.app.modular.object.service.ObjectService;
import cn.jetpiece.cloud.model.exception.ServiceException;
import cn.jetpiece.cloud.model.response.Result;
import cn.jetpiece.cloud.redis.utils.RedisUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@AllArgsConstructor
public class JossObjectController implements JossObjectApi {
    private final BucketService bucketService;
    private final ObjectService objectService;

    @Override
    public Result<UploadObjectResult> postObject(JossPostObject params, MultipartFile file, List<JossPartEtag> etag) {
        String requestUri = HttpContext.getRequest().getRequestURI();
        if (requestUri.startsWith("joss/")) {
            requestUri = requestUri.replaceFirst("joss/", "");
        }
        if (requestUri.startsWith("/joss/")) {
            requestUri = requestUri.replaceFirst("/joss/", "");
        }
        String bucketName = requestUri.substring(0, requestUri.indexOf(OssConstants.PATH_SEPARATE));
        String objectName = requestUri.substring(requestUri.indexOf(OssConstants.PATH_SEPARATE));
        BucketInfo bucketInfo = bucketService.getBucket(bucketName);
        if (bucketInfo == null || bucketInfo.getIsEnable().equals(0)) {
            throw new ServiceException(BasicExceptionEnum.BUCKET_NOT_EXISTED);
        }

        if (params.getPreSign() != null) {
            String uuid = getPreToken(requestUri, params.getPreExpires());
            UploadObjectResult uploadObjectResult = new UploadObjectResult();
            uploadObjectResult.setJossToken(uuid);
            uploadObjectResult.setUrl(objectService.getObjectUrl(bucketName, objectName));
            return Result.OK(uploadObjectResult);
        }
        if (params.getUploads() != null) {
            InitMultiPartUploadObject initMultiPartUploadObject = new InitMultiPartUploadObject();
            initMultiPartUploadObject.setBucketName(bucketName);
            initMultiPartUploadObject.setAcl(params.getAcl());
            initMultiPartUploadObject.setContentType(params.getContentType());
            String uploadId = objectService.initMultipartUpload(objectName, initMultiPartUploadObject, bucketInfo);
            UploadObjectResult uploadObjectResult = new UploadObjectResult();
            uploadObjectResult.setUploadId(uploadId);
            return Result.OK(uploadObjectResult);
        }
        if (StrUtil.isNotBlank(params.getUploadId())) {
            /* 分片合并 */
            try {
                CompleteMultiPartUploadObject completeMultiPartUploadObject = new CompleteMultiPartUploadObject();
                completeMultiPartUploadObject.setUploadId(params.getUploadId());
                completeMultiPartUploadObject.setEtag(etag);
                return objectService.completeMultipartUpload(objectName, completeMultiPartUploadObject, bucketInfo);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new ServiceException(500, "合并分片失败!");
            }
        }
        throw new ServiceException(500, "不支持的请求!");
    }

    @Override
    public Result<UploadObjectResult> putObject(JossPutObject params, MultipartFile file) {
        String requestUri = HttpContext.getRequest().getRequestURI();
        if (requestUri.startsWith("joss/")) {
            requestUri = requestUri.replaceFirst("joss/", "");
        }
        if (requestUri.startsWith("/joss/")) {
            requestUri = requestUri.replaceFirst("/joss/", "");
        }
        String bucketName = requestUri.substring(0, requestUri.indexOf(OssConstants.PATH_SEPARATE));
        String objectName = requestUri.substring(requestUri.indexOf(OssConstants.PATH_SEPARATE));
        BucketInfo bucketInfo = bucketService.getBucket(bucketName);
        if (bucketInfo == null || bucketInfo.getIsEnable().equals(0)) {
            throw new ServiceException(BasicExceptionEnum.BUCKET_NOT_EXISTED);
        }
        if (StrUtil.isNotBlank(params.getUploadId())) {
            MultiPartUploadObject multiPartUploadObject = new MultiPartUploadObject();
            multiPartUploadObject.setBucketName(bucketName);
            multiPartUploadObject.setPartNumber(params.getPartNumber());
            multiPartUploadObject.setPartSize(params.getPartSize());
            multiPartUploadObject.setOffset(params.getOffset());
            multiPartUploadObject.setContentMd5(params.getContentMd5());
            multiPartUploadObject.setUploadId(params.getUploadId());
            UploadObjectResult uploadObjectResult = new UploadObjectResult();
            uploadObjectResult.setEtag(objectService.multipartUpload(objectName, multiPartUploadObject, bucketInfo, file));
            return Result.OK(uploadObjectResult);
        }
        PutObject putObject = new PutObject();
        putObject.setPutObjectMode(params.getModel());
        putObject.setBucketName(bucketName);
        putObject.setAcl(params.getAcl());
        putObject.setContentType(params.getContentType());
        putObject.setPutObjectMode(params.getModel());
        return objectService.putObject(objectName, putObject, bucketInfo, file);
    }

    @Override
    public void getObject(GetObject params) {
        String requestUri = HttpContext.getRequest().getRequestURI();
        if (requestUri.startsWith("joss/")) {
            requestUri = requestUri.replaceFirst("joss/", "");
        }
        if (requestUri.startsWith("/joss/")) {
            requestUri = requestUri.replaceFirst("/joss/", "");
        }
        String bucketName = requestUri.substring(0, requestUri.indexOf(OssConstants.PATH_SEPARATE));
        String objectName = requestUri.substring(requestUri.indexOf(OssConstants.PATH_SEPARATE));
        BucketInfo bucketInfo = bucketService.getBucket(bucketName);
        if (bucketInfo == null || bucketInfo.getIsEnable().equals(0)) {
            throw new ServiceException(BasicExceptionEnum.BUCKET_NOT_EXISTED);
        }
        if (params.getPreSign() != null) {
            String uuid = getPreToken(requestUri, params.getPreExpires());
            setResponse(bucketName, objectName, uuid);
            return;
        }
        objectService.getObject(objectName, bucketInfo);
    }

    /**
     * 获取临时token
     *
     * @param requestUri 请求链接
     * @param expires    超时时间
     */
    private String getPreToken(String requestUri, Long expires) {
        if (AuthUtil.isNotAuth()) {
            throw new ServiceException(BasicExceptionEnum.FORBIDDEN);
        }
        try {
            String uuid = UUID.fastUUID().toString();
            RedisUtil redisUtil = RedisUtil.getInstance();
            if (expires == null) {
                expires = OssProperties.getInstance().getPreExpires();
            }
            redisUtil.getRedisTemplate().opsForValue().set(OssConstants.JOSS_TOKEN_CACHE + uuid, "/" + requestUri, expires, TimeUnit.SECONDS);
            return uuid;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(500, "生成预Token失败");
        }
    }

    private void setResponse(String bucketName, String objectName, String uuid) {
        PrintWriter writer = null;
        try {
            HttpServletResponse response = HttpContext.getResponse();
            UploadObjectResult uploadObjectResult = new UploadObjectResult();
            uploadObjectResult.setJossToken(uuid);
            uploadObjectResult.setUrl(objectService.getObjectUrl(bucketName, objectName));
            response.setStatus(200);
            response.setContentType(MediaType.APPLICATION_JSON_VALUE);
            writer = response.getWriter();
            writer.print(JSONObject.toJSONString(uploadObjectResult));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ServiceException(500, "生成预Token失败");
        } finally {
            if (writer != null) {
                writer.flush();
            }
        }
    }

    @Override
    public Result<String> deleteObject() {
        String requestUri = HttpContext.getRequest().getRequestURI();
        if (requestUri.startsWith("joss/")) {
            requestUri = requestUri.replaceFirst("joss/", "");
        }
        if (requestUri.startsWith("/joss/")) {
            requestUri = requestUri.replaceFirst("/joss/", "");
        }
        String bucketName = requestUri.substring(0, requestUri.indexOf(OssConstants.PATH_SEPARATE));
        String objectName = requestUri.substring(requestUri.indexOf(OssConstants.PATH_SEPARATE));
        BucketInfo bucketInfo = bucketService.getBucket(bucketName);
        if (bucketInfo == null || bucketInfo.getIsEnable().equals(0)) {
            throw new ServiceException(BasicExceptionEnum.BUCKET_NOT_EXISTED);
        }
        objectService.deleteObject(objectName, bucketInfo);
        return Result.OK("删除成功");
    }

}
